#pragma  once

//#define GL_VERSION_2_0_PROTOTYPES
//#include "./../Framework/OpenGL/Extensions/GLExtensions.h"
#include <vector>
#include <list>

#include <map>

#include "GL/glew.h"

#include <cmath>

class eyePosition;

class AppGloble
{	
public :
	static const float PI;

	static int frameRendered;//记录帧率

	static int curFPS; 
	static GLuint theVShader;		//vs代码段
	static GLuint thePShader;		//ps代码段
	static GLuint prgrm;			//可用于替换固定流水线的glsl 代码段

	static float crateUniformShader;

	static GLint crateLoc;
	static float crateValue;

	static GLint terrainTexloc;
	static float maxHightValue;

	static GLint colorTexloc;

	static GLint maxHightloc;

	static GLint eyeposloc;
	static eyePosition noweye;
	
	static GLint isDetailloc;
	static GLint isDetail;//1 detail 0 not

	static GLint isColorTexUseloc;
	static GLint isColorTexUse;//1 use 0 not


	static GLint renderSizexLoc;
	static float renderSizex;
	
	static GLint renderSizeyLoc;
	static float renderSizey;

	static bool drawFillMode;
	static bool usingLigting;

	static float axlength;

	static GLuint fuzuCallListNum;
	static GLuint terrainCallListNum;
	static GLuint terrainDetailCallListNum;
	static GLuint terrainMoreDetailCallListNum;
	static GLuint textureNUM;
	static GLuint tmpTextureNUM;
	static GLuint terrianTextureNUM;	

	static bool ldown;
	static int mdownXpos;
	static int mdownYpos;

	static float oldLong;
	static float oldLat;

	static bool rdown;
	static float oldRadius;

	static bool usingGLSL20;

	static unsigned int mapSizex;
	static unsigned int mapSizey;

	static bool holePointsVec;
	static bool detailPrint;
	static bool usingColorTex;

	static bool coordAxixNeed;
	static bool sceneInfNeed;

	static long totalTriCount;	

	static int detailGridNum;

	static int roamDividDepth;

	static float eyetox;
	static float eyetoy;


	static GLint MST_zoomLOC;
	static float MST_zoom;

	static GLint MST_xcenLOC;
	static float MST_xcen;

	static GLint MST_ycenLOC;
	static float MST_ycen;

	static GLint MST_inixLOC;
	static float MST_inix;

	static GLint MST_iniyLOC;
	static float MST_iniy;

	static GLint MST_maxforNumLOC;
	static float MST_maxforNum;
};

struct gridPoint
{
	float cx;
	float cy;
	float hv;
	float qfv;

	gridPoint()
	{
	}

	gridPoint(float _cx, float _cy, float _hv)
	{
		cx = _cx;
		cy = _cy;
		hv = _hv;
	}
};

typedef struct gridPoint gpoint;

class nonuniformTriangle
{
	const gpoint *p1, *p2, *p3;
	float centerx, centery;
	float rediusSQ;

public:
	nonuniformTriangle(const gpoint *inp1,  const gpoint *inp2, const gpoint *inp3);	
	nonuniformTriangle(const nonuniformTriangle& theTriangle);
	nonuniformTriangle& operator =(const nonuniformTriangle& theTriangle);//一般情况下几乎总要遵循operator=输入和返回的都是类对象的引用的原则
	void computeCircle();
	bool isInCircle(const gpoint &inp);
	bool isInCircle(const gpoint *inp);
	static const float inDst;

	const gpoint * getP1(){return this->p1;}
	const gpoint * getP2(){return this->p2;}
	const gpoint * getP3(){return this->p3;}

};

typedef class nonuniformTriangle nutrian;

class eyePosition
{
public :
	float eyex, eyey, eyez;
	float longitude;	//经度 0 到 pi
	float latitude;		//纬度 -pi/2 到 pi/2
	float radius;

	eyePosition()
	{
		defaultPos();
	}

	void defaultPos()
	{
		longitude = AppGloble::PI/4.0f;

		latitude = AppGloble::PI/4.0f;

		radius = 10.0f;		

		computPosXYZ();
	}

	void computPosXYZ()
	{
		if(radius<0)
			radius = -radius;

		eyez = radius*sin(latitude);

		float radiusOnXOY = radius*cos(latitude);

		eyex =  radiusOnXOY*cos(longitude);

		eyey =  radiusOnXOY*sin(longitude);
	}	
};

//typedef std::pair<float, float> pointPair;
enum TriAglDrct						//直角三角形斜边中，到直角顶点的连线指向的方向
{		
		TriAglDrct_UP=0,
		TriAglDrct_UPRIGHT=1,
		TriAglDrct_RIGHT=2,
		TriAglDrct_DOWNRIGHT=3,
		TriAglDrct_DOWN=4,
		TriAglDrct_DOWNLEFT=5,
		TriAglDrct_LEFT=6,
		TriAglDrct_UPLEFT=7
};

enum DividPoint						//剖分点的位置
{
		RTNDPDOWN,							//直角三角形斜边中点
		RTNDPLEFT,							//直角三角形斜边中，到直角顶点的连线指向的方向 左边中点
		RTNDPRIGHT							//直角三角形斜边中，到直角顶点的连线指向的方向 右边中点
};

//========================================ROAM算法实现的核心数据结构，二元三角树 
class roamTreeNode 
{
public:


	roamTreeNode(TriAglDrct tdrct, float pointAx, float pointAy, float thelenT);

	roamTreeNode(roamTreeNode* theParent, bool isLeft, int newPAindex); 

	~roamTreeNode()
	{
		if(LeftChild!=NULL)
		{
			delete LeftChild;
		}

		if(RightChild!=NULL)
		{
			delete RightChild;
		}	
	}

	static float* dataBlob;	
	static float renderSizex;
	static float renderSizey;

	static int lenx;
	static int leny;

	bool linkNodes(roamTreeNode* anotherNode);

	void doDivid(DividPoint theDPoint);	

	void doDividWithBreakPointReady(DividPoint theDPoint,int breakPointIndex);


	void travelChildren();

	//void travelChildrenToCreateGrid(std::vector<float>& trpcds);

	void travelChildrenToCreateGrid(std::vector<int>& trpcds);

	TriAglDrct getTriDrct(){return this->theDrct;}
	int getDetailLevel(){return this->detailLevel;}

	float getpAx(){return this->points[pA].cx;}
	float getpAy(){return this->points[pA].cy;}
	float getpAZ(){return this->points[pA].hv;}
	
	float getpBx(){return this->points[pB].cx;}
	float getpBy(){return this->points[pB].cy;}
	float getpBz(){return this->points[pB].hv;}
	
	float getpCx(){return this->points[pC].cx;}
	float getpCy(){return this->points[pC].cy;}
	float getpCz(){return this->points[pC].hv;}

	float getLenT(){return this->lenT;}	

	roamTreeNode * getLCNode(){return LeftChild;}

	roamTreeNode * getRCNode(){return RightChild;}

	static std::vector<gpoint > points;//所有的节点坐标

protected:	

	roamTreeNode *parentNode;			//三角形父节点

	roamTreeNode *LeftChild;			//左子三角形节点

	roamTreeNode *RightChild;			//右子三角形节点

	roamTreeNode *BaseNeighbor;			//底边邻接三角形节点

	roamTreeNode *LeftNeighbor;			//左边邻接三角形节点

	roamTreeNode *RightNeighbor;		//右边邻接三角形节点

	TriAglDrct theDrct;					//当前三角型的朝向

	int detailLevel;					//当前node的细节数，每被剖分一次，该细节数加一

	int pA;								//直角所在顶点下标	
	int pB;								//按右手定则，从直角所在顶点开始，另一个顶点下标
	int pC;								//最后一个顶点下标
	
	float lenT;

	float roughDegreeCount;
};



void drawModel();

void keyFunc(unsigned char key, int x, int y);
void keyFunc_mandelbort(unsigned char key, int x, int y);
void mouseFunc(int button, int state, int x, int y);
void mouseMotionFunc(int x, int y);
void changePolygonMode();
void eyeDrawSet();
void computFrameRate(int value);
void drawCoordAxis();
void showScenInf();

bool shaderSet();
bool shaderSetMandelbrotSet();

void lightAndMatSet();
void texSet();

void detailTerrainGridCreate();
void moreDetailTerrainGridCreate();

void drawModel_terrain();
void texSet_terrian(unsigned char*);
bool shaderSet_terrian();

void terrianGridCreate_fix_();
void terrianGridCreate_();

bool nonUniformTerrainGridCreate(unsigned char* dataBlob, 
								 const int lenx, 
								 const int leny, 
								 const float renderSizex = 3.0f,
								 const float renderSizey = 3.0f,
								 const float roughDegree = 0.1f);

bool doDelaunay(std::vector<const gpoint* > & thePointSet, std::list<nutrian> &untriangles);

bool trangleFansTerrainGridCreate(unsigned char* dataBlob, const int lenx, const int leny);

bool RoamTrianglesCreate(unsigned char* dataBlob, 
						 const int lenx, 
						 const int leny, 
						 const float renderSizex = 3.0f,
						 const float renderSizey = 3.0f,
						 const float roughDegree = 0.1f);

//====================sigle test demos===============================================

int demo_Mandelbrot();
int demo_twoPass();
